﻿using System;
using System.Data;
using System.IO;
using System.Reflection;
using System.Net.Mail;
using System.Net;
using System.Text;
using System.Collections;
using System.Xml;
using System.Configuration;
using System.Management;
using System.Threading;
using System.Xml.Xsl;

namespace LoadTestingEmailRepoter.PulgIn
{
    public class Utilities
    {
        public static void WriteToFile(string fileName, string text)
        {
            if (!fileName.EndsWith(@"\")) fileName += @"\";
            fileName += "Load Test " + DateTime.Now.ToString().Replace("/", "-").Replace(":", "-").Replace(" ", "-") + ".html";

            FileStream fStream = new FileStream(fileName, FileMode.Create, FileAccess.Write);
            BufferedStream bfs = new BufferedStream(fStream);
            StreamWriter sWriter = new StreamWriter(bfs);
            sWriter.WriteLine(text);
            sWriter.Close();

        }

        /// <summary>
        /// Initializes a new instance of the <see cref="HTMLUtils"/> class.
        /// </summary>
        public Utilities()
        {
            sb = new System.Text.StringBuilder();
        }

        #region Data

        System.Text.StringBuilder sb;

        const string tableStartText = "<Table cellSpacing=0 cellPadding=3 width=100% border=0>";
        const string tableEndText = "</Table>";

        /// <summary>
        /// Gets the formatted HTML text.
        /// </summary>
        /// <value>The formatted HTML text.</value>
        public string FormattedHtmlText
        {
            get
            {
                sb.Insert(0, tableStartText);
                sb.Append(tableEndText);
                return sb.ToString();
            }
        }

        #endregion

        #region Predefined Text Size Area

        /// <summary>
        /// Formats to a html row with the text with 4 size text
        /// </summary>
        /// <param name="text">The text.</param>
        public void AppendHeader(string text)
        {
            FormatToRow(text, 4, true);
        }

        /// <summary>
        /// Formats to a html row with the text with 3 size text
        /// </summary>
        /// <param name="text">The text.</param>
        public void AppendSubHeader(string text)
        {
            FormatToRow(text, 3, true);
        }

        /// <summary>
        /// Formats to a html row with the text with 2 size text
        /// </summary>
        /// <param name="text">The text.</param>
        public void AppendPara(string text)
        {
            FormatToRow(text, 2, false);
        }

        /// <summary>
        /// Appends the blank row.
        /// </summary>
        public void AppendBlankRow()
        {
            FormatToBlankRow();
        }

        #endregion

        #region Format Area

        /// <summary>
        /// Formats a blank HTML row.
        /// </summary>
        public void FormatToBlankRow()
        {
            sb.Append("<TR> <TD height=20> </TD> </TR>");
        }

        /// <summary>
        /// Formats to row.
        /// </summary>
        /// <param name="text">The text.</param>
        public void FormatToRow(string text)
        {
            FormatToRow(text, 2, false);
        }

        /// <summary>
        /// Formats to row.
        /// </summary>
        /// <param name="text">The text.</param>
        /// <param name="fontSize">Size of the font.</param>
        public void FormatToRow(string text, int fontSize)
        {
            FormatToRow(text, fontSize, false);
        }

        /// <summary>
        /// Formats to row.
        /// </summary>
        /// <param name="text">The text.</param>
        /// <param name="fontSize">Size of the font.</param>
        /// <param name="bold">if set to <c>true</c> [bold].</param>
        public void FormatToRow(string text, int fontSize, bool bold)
        {
            string boldMarker = (bold ? "bold" : "normal");
            string fontFace = "verdana";
            sb.Append("<TR> <TD align=left><font size=" + fontSize.ToString(System.Globalization.CultureInfo.CurrentCulture.NumberFormat) + " face=" + fontFace + " style=\"FONT-WEIGHT: " + boldMarker + "\"  > " + text + "</font></TD> </TR>");
        }

        /// <summary>
        /// Formats the provided key/values by separating them thru a colon, and considers the smallest text size '2'.
        /// </summary>
        /// <param name="strLabel"></param>
        /// <param name="strValue"></param>
        public void FormatToRowInColonSeparatedText(string label, string value)
        {
            FormatToRowInColonSeparatedText(label, value, false);
        }

        /// <summary>
        /// Formats the provided key/values by separating them thru a colon, and considers the smallest text size '2'.
        /// </summary>
        /// <param name="strLabel"></param>
        /// <param name="strValue"></param>
        /// <param name="bold"></param>
        public void FormatToRowInColonSeparatedText(string label, string value, bool bold)
        {
            label = "<b>" + label + " : </b>";
            if (bold) value = "<b>" + value + "</b>";
            FormatToRow(label + " " + value, 2, bold);
        }

        #endregion

        public static string ConvertDataTableToHtmlTable(DataTable dt)
        {
            string table = "<table><tr>";
            foreach (DataColumn column in dt.Columns)
                table += "<td>" + column.ColumnName + "</td>";

            table += "</tr>";

            foreach (DataRow row in dt.Rows)
            {
                table += "<tr>";

                foreach (DataColumn column in dt.Columns)
                    table += "<td>" + row[column].ToString() + "</td>";

                table += "</tr>";
            }

            table += "</table>";

            return table;
        }

        public static string ReadDataFromFile(string filePath)
        {
            FileStream fStream;

            // Reading the file content.
            fStream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Read);
            StreamReader sReader = new StreamReader(fStream);
            string line = sReader.ReadToEnd();
            sReader.Close();

            return line;
        }


        public static string LoadDefaultSqlScript()
        {
            return GetResource("Ashraf.LoadTesting.utils.Report.sql");
        }

        public static string GetResource(string resourceName)
        {
            Assembly assembly = Assembly.GetExecutingAssembly();
            TextReader textReader = new StreamReader(assembly.GetManifestResourceStream(resourceName));
            string result = textReader.ReadToEnd();
            textReader.Close();
            return result;
        }

        /// <summary>
        /// exemplary call: GetSystemInfo("Win32_Processor", "Caption,Manufacturer");
        /// http://www.codeproject.com/KB/system/GetHardwareInformation.aspx
        /// </summary>
        /// <param name="strTable"></param>
        /// <param name="strProperties"></param>
        /// <returns></returns>
        public static string GetSystemInfo(string strTable, string strProperties)
        {
            try
            {
                ManagementObjectSearcher mos = new ManagementObjectSearcher();
                mos.Query.QueryString = "SELECT " + strProperties + " FROM " + strTable;
                ManagementObjectCollection moc = mos.Get();
                string strInfo = string.Empty;
                foreach (ManagementObject mo in moc)
                    foreach (PropertyData pd in mo.Properties)
                        strInfo += pd.Value + ",";
                return strInfo.Substring(0, strInfo.Length - 1);
            }
            catch { return "Invalid table or properties"; }
        }
    }

    public class Emailer
    {
        public static void SendMail(string subject, string body, Stream attachment)
        {
            MailMessage mailMsg = new MailMessage();
            mailMsg.From = new MailAddress(AppReader.EmailReporterFromEmail);
            mailMsg.To.Add(AppReader.EmailReporterNotifyEmail);
            mailMsg.Subject = subject;
            mailMsg.IsBodyHtml = true;
            mailMsg.BodyEncoding = Encoding.UTF8;
            mailMsg.Body = body;
            mailMsg.Priority = MailPriority.Normal;

            //Message attahment
            if (attachment != null)
                mailMsg.Attachments.Add(new Attachment(attachment, "Load Test Report " + DateTime.Now + ".xls"));

            // Smtp configuration
            SmtpClient client = new SmtpClient();
            client.Credentials = new NetworkCredential(AppReader.EmailReporterSmtpServerUserName, AppReader.EmailReporterSmtpServerPassword);
            client.Port = AppReader.EmailReporterSmtpServerPort; //use 465 or 587 for gmail           
            client.Host = AppReader.EmailReporterSmtpServer;
            client.EnableSsl = AppReader.EmailReporterRequiredSsl;
            object userState = mailMsg;
            try
            {
                //you can also call client.Send(msg)
                client.Send(mailMsg);
            }
            catch (SmtpException ex)
            {
                System.Windows.Forms.MessageBox.Show("Error while sending email. Please check you have provided required values for email related attributes, such as: EmailReporterNotifyEmail, EmailReporterFromEmail, EmailReporterSmtpServer, EmailReporterSmtpServerPort, EmailReporterSmtpServerUserName, EmailReporterSmtpServerPassword OR EmailReporterRequiredSSL." + ex.ToString());
            }
        }
    }

    public sealed class AppReader
    {
        AppReader() { }

        public static float TestReportDelayInSeconds
        {
            get
            {
                string s = GetConfigValue("TestReportDelayInSeconds");
                float i = 0;
                if (string.IsNullOrEmpty(s))
                    i = 1;
                else
                    i = float.Parse(s);
                return i;
            }
        }

        public static string CustomReportSqlFilePath
        {
            get
            {
                return GetConfigValue("CustomReportSqlFilePath");
            }
        }

        public static string LocalReportDirectory
        {
            get
            {
                return GetConfigValue("LocalReportDirectory");
            }
        }

        public static string WebSiteName
        {
            get
            {
                return GetConfigValue("WebSiteName");
            }
        }

        public static string EmailReporterNotifyEmail
        {
            get
            {
                string s = GetConfigValue("EmailReporterNotifyEmail");
                if (string.IsNullOrEmpty(s))
                    ShowMessage("EmailReporterNotifyEmail");

                return s;
            }
        }

        public static string EmailReporterFromEmail
        {
            get
            {
                string s = GetConfigValue("EmailReporterFromEmail");
                if (string.IsNullOrEmpty(s))
                    return EmailReporterNotifyEmail;

                return s;
            }
        }

        public static string EmailReporterSmtpServer
        {
            get
            {
                string s = GetConfigValue("EmailReporterSmtpServer");
                if (string.IsNullOrEmpty(s))
                    s = "localhost";

                return s;
            }
        }

        public static int EmailReporterSmtpServerPort
        {
            get
            {
                string s = GetConfigValue("EmailReporterSmtpServerPort");
                if (string.IsNullOrEmpty(s))
                    return 25;//default smtp port

                return int.Parse(s);
            }
        }

        public static string EmailReporterSmtpServerUserName
        {
            get
            {
                return GetConfigValue("EmailReporterSmtpServerUserName");
            }
        }

        public static string EmailReporterSmtpServerPassword
        {
            get
            {
                return GetConfigValue("EmailReporterSmtpServerPassword");
            }
        }

        public static bool EmailReporterRequiredSsl
        {
            get
            {
                string s = GetConfigValue("EmailReporterRequiredSSL");
                if (string.IsNullOrEmpty(s))
                    s = "false";
                return s == "true";
            }
        }

        public static bool EmailReporterDisabled
        {
            get
            {
                string s = GetConfigValue("EmailReporterDisabled");
                if (string.IsNullOrEmpty(s))
                    s = "False";
                return s == "True";
            }
        }

        public static bool AttachExcelReport
        {
            get
            {
                string s = GetConfigValue("AttachExcelReport");
                if (string.IsNullOrEmpty(s))
                    s = "False";

                return s == "True";
            }
        }

        public static string LoadTestDb
        {
            get
            {
                string s = GetConfigValue("LoadTestDb");
                if (string.IsNullOrEmpty(s))
                    ShowMessage("LoadTestDb");

                return s;
            }
        }

        public static string GetConfigValue(string key)
        {
            FileInfo fileInfo = new FileInfo("App.config");
            ConfigurationFileReader f = new ConfigurationFileReader(fileInfo.FullName);
            return f.GetParameter(key);
        }

        public static void ShowMessage(string key)
        {
            System.Windows.Forms.MessageBox.Show("Required entry for '" + key + "' key at App.Config is missing. Please add this key and corresponding email address under configuration/appSettings section in App.Config file of your test project. Report will NOT be sent.");
        }
    }

    public class ConfigurationFileReader
    {
        #region Public Properties

        /// <summary>
        /// Contains the first error message that may have occured.
        /// </summary>
        public string Error
        {
            get { return _FirstMajorError.ToString(); }
            set
            {
                if (_FirstMajorError.Length == 0)
                    _FirstMajorError.Append(value);
            }
        }
        private StringBuilder _FirstMajorError = new StringBuilder();

        /// <summary>
        /// Denotes if an error has occurred.
        /// </summary>
        public bool IsError
        {
            get { return _IsError; }
            set { _IsError = value; }
        }
        private bool _IsError = false;

        #endregion

        #region Private Properties
        private System.Collections.Specialized.NameValueCollection RunParameters = new System.Collections.Specialized.NameValueCollection();
        private StringBuilder TagName = new StringBuilder();
        private StringBuilder TagValue = new StringBuilder();
        private System.Diagnostics.EventLog EventLog1 = new System.Diagnostics.EventLog();

        #endregion

        public ConfigurationFileReader(string ConfigurationFilename)
        {
            EventLog1.Source = "ConfigurationFileReader";
            RunParameters.Clear();
            Error = "";
            IsError = false;
            if (ConfigurationFilename.Trim().Length == 0)
            {
                SetError("Configuration file required.");
                return;
            }

            try
            {
                if (File.Exists(ConfigurationFilename))
                    ProcessParameterData(ConfigurationFilename);
                else
                    SetError("File " + ConfigurationFilename + " does not exist.");
            }
            catch (Exception ex)
            {
                SetError("Error while processing parm file " + ConfigurationFilename + " in " + ((MethodInfo)MethodBase.GetCurrentMethod()).ToString() + ".\n" + ex.Message);
                WriteEventEntryError("Error while processing parm file " + ConfigurationFilename + " in " + ((MethodInfo)MethodBase.GetCurrentMethod()).ToString() + ".\n" + ex.Message);
            }

        } //ends constructor


        /// <summary>
        /// Retrieves the value of the requested parameter.
        /// <p></p>
        /// An empty string is returned if the requested key is not present.
        /// </summary>
        /// <param name="WhichKey">Key to get</param>
        /// <returns>String data value</returns>
        public string GetParameter(string WhichKey)
        {
            return GetParameter(WhichKey, string.Empty);
        } //ends GetParameter

        /// <summary>
        /// Retrieves the value of the requested parameter or returns
        /// the DefaultValue if the requested parmameter is missing or empty.
        /// </summary>
        /// <param name="WhichKey">Key to get</param>
        /// <param name="DefaultValue">Default value to return if requested parm not present</param>
        /// <returns>String data value or default value</returns>
        public string GetParameter(string WhichKey, string DefaultValue)
        {
            if (GetParameterFromNVC(WhichKey).Trim().Length > 0)
                return GetParameterFromNVC(WhichKey);
            return DefaultValue;
        } //ends GetParameter


        /// <summary>
        /// Retrieves the value of the requested parm.
        /// </summary>
        /// <param name="WhichKey">Key to get</param>
        /// <returns>String data value</returns>
        private string GetParameterFromNVC(string WhichKey)
        {
            try
            {
                if (!(RunParameters[WhichKey.ToLower()] == null))
                    return RunParameters[WhichKey.ToLower()];
            }
            catch { }
            return "";
        } //ends GetParameterFromNVC


        /// <summary>
        /// Spin through the config xml file looking for the specific types of
        /// parms we are looking for.
        /// <para></para>
        /// The format MUST be 
        /// &lt;parm key="somename"  value="somevalue"  /&gt;
        /// <para></para>
        /// Parms with only a key attribute will have the value set to true.
        /// </summary>
        /// <param name="inName"></param>
        private void ProcessParameterData(string inName)
        {
            try
            {
                if (File.Exists(inName))
                {
                    IDictionary appSettingsDictionary = null;
                    try
                    {
                        #region Read parms from file
                        XmlDocument configXml = new XmlDocument();
                        XmlTextReader configXmlReader = new XmlTextReader(inName);
                        configXml.Load(configXmlReader);
                        configXmlReader.Close();
                        XmlNodeList configNodes = configXml.GetElementsByTagName("appSettings");
                        foreach (XmlNode configNode in configNodes)
                        {
                            if (configNode.LocalName == "appSettings")
                            {
                                DictionarySectionHandler handler = new DictionarySectionHandler();
                                appSettingsDictionary = (IDictionary)handler.Create(null, null, configNode);
                                break;
                            }
                        }
                        #endregion
                        if (!(appSettingsDictionary == null))
                        {
                            foreach (string k in appSettingsDictionary.Keys)
                            {
                                RunParameters.Add(k, appSettingsDictionary[k].ToString());
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        SetError("Error 1 while processing parm file " + inName + " in " + ((MethodInfo)MethodBase.GetCurrentMethod()).ToString() + "\n" + ex.Message);
                    }
                }
                else
                {
                    WriteEventEntryError("file " + inName + " does not exist.\n" + ((MethodInfo)MethodBase.GetCurrentMethod()).ToString());
                }
            }
            catch (Exception ex)
            {
                SetError("Error 2 while processing parm file " + inName + " in " + ((MethodInfo)MethodBase.GetCurrentMethod()).ToString() + "\n" + ex.Message);
            }
        }  //ends ProcessParameterData


        /// <summary>
        /// Set the error message field and switch.
        /// </summary>
        /// <param name="s"></param>
        private void SetError(string s)
        {
            Error = s;
            IsError = true;
        } //ends SetError


        /// <summary>
        /// Put an entry in the application event log.
        /// </summary>
        /// <param name="s"></param>
        private void WriteEventEntryError(string s)
        {
            EventLog1.WriteEntry(s, System.Diagnostics.EventLogEntryType.Error);
        } //ends WriteEventEntryError

    }

    public class Export
    {
        #region CreateStylesheet

        // Function  : WriteStylesheet 
        // Arguments : writer, sHeaders, sFileds, FormatType
        // Purpose   : Creates XSLT file to apply on dataset's XML file 

        private static void CreateStylesheet(XmlTextWriter writer, string[] sHeaders, string[] sFileds)
        {
            try
            {
                // xsl:stylesheet
                string ns = "http://www.w3.org/1999/XSL/Transform";
                writer.Formatting = Formatting.Indented;
                writer.WriteStartDocument();
                writer.WriteStartElement("xsl", "stylesheet", ns);
                writer.WriteAttributeString("version", "1.0");
                writer.WriteStartElement("xsl:output");
                writer.WriteAttributeString("method", "text");
                writer.WriteAttributeString("version", "4.0");
                writer.WriteEndElement();

                // xsl-template
                writer.WriteStartElement("xsl:template");
                writer.WriteAttributeString("match", "/");

                // xsl:value-of for headers
                for (int i = 0; i < sHeaders.Length; i++)
                {
                    writer.WriteString("\"");
                    writer.WriteStartElement("xsl:value-of");
                    writer.WriteAttributeString("select", "'" + sHeaders[i] + "'");
                    writer.WriteEndElement(); // xsl:value-of
                    writer.WriteString("\"");
                    if (i != sFileds.Length - 1) writer.WriteString("	");
                }

                // xsl:for-each
                writer.WriteStartElement("xsl:for-each");
                writer.WriteAttributeString("select", "Export/Values");
                writer.WriteString("\r\n");

                // xsl:value-of for data fields
                for (int i = 0; i < sFileds.Length; i++)
                {
                    writer.WriteString("\"");
                    writer.WriteStartElement("xsl:value-of");
                    writer.WriteAttributeString("select", sFileds[i]);
                    writer.WriteEndElement(); // xsl:value-of
                    writer.WriteString("\"");
                    if (i != sFileds.Length - 1) writer.WriteString("	");
                }

                writer.WriteEndElement(); // xsl:for-each
                writer.WriteEndElement(); // xsl-template
                writer.WriteEndElement(); // xsl:stylesheet
                writer.WriteEndDocument();
            }
            catch (Exception Ex)
            {
                throw Ex;
            }
        }

        #endregion // WriteStylesheet

        #region Memory Steam Related

        public static MemoryStream ExportToMemory(DataTable DetailsTable)
        {
            try
            {
                if (DetailsTable.Rows.Count == 0)
                    throw new Exception("There are no details to export.");

                // Create Dataset
                DataSet dsExport = new DataSet("Export");
                DataTable dtExport = DetailsTable.Copy();
                dtExport.TableName = "Values";
                dsExport.Tables.Add(dtExport);

                // Getting Field Names
                string[] sHeaders = new string[dtExport.Columns.Count];
                string[] sFileds = new string[dtExport.Columns.Count];

                for (int i = 0; i < dtExport.Columns.Count; i++)
                {
                    sHeaders[i] = dtExport.Columns[i].ColumnName;
                    sFileds[i] = dtExport.Columns[i].ColumnName;
                }

                return GetMemoryStream(dsExport, sHeaders, sFileds);
            }
            catch (Exception Ex)
            {
                throw Ex;
            }
        }

        private static MemoryStream GetMemoryStream(DataSet dsExport, string[] sHeaders, string[] sFileds)
        {
            try
            {
                MemoryStream stream = new MemoryStream();
                XmlTextWriter writer = new XmlTextWriter(stream, Encoding.UTF8);

                CreateStylesheet(writer, sHeaders, sFileds);
                writer.Flush();
                stream.Seek(0, SeekOrigin.Begin);

                XmlDataDocument xmlDoc = new XmlDataDocument(dsExport);
                XslTransform xslTran = new XslTransform();
                xslTran.Load(new XmlTextReader(stream), null, null);

                System.IO.StringWriter sw = new System.IO.StringWriter();
                xslTran.Transform(xmlDoc, null, sw, null);

                //Writeout the Content				
                string s = sw.ToString();
                sw.Close();
                writer.Close();
                stream.Close();

                //convert to memory
                byte[] b = new System.Text.ASCIIEncoding().GetBytes(s);
                MemoryStream m = new MemoryStream(b);
                return m;
            }
            catch (ThreadAbortException Ex)
            {
                string ErrMsg = Ex.Message;
            }
            catch (Exception Ex)
            {
                throw Ex;
            }

            return null;
        }

        #endregion

    }
}